package cn.com.dcsgo.service.impl;

import cn.com.dcsgo.domain.SysUserRole;
import cn.com.dcsgo.dto.PageDTO;
import cn.com.dcsgo.dto.SysUserAddDTO;
import cn.com.dcsgo.dto.SysUserQueryDTO;
import cn.com.dcsgo.dto.SysUserUpdateDTO;
import cn.com.dcsgo.exception.BusinessException;
import cn.com.dcsgo.mapper.SysUserRoleMapper;
import cn.com.dcsgo.utils.AuthUtil;
import cn.com.dcsgo.vo.SysUserVO;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.com.dcsgo.domain.SysUser;
import cn.com.dcsgo.service.SysUserService;
import cn.com.dcsgo.mapper.SysUserMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashSet;
import java.util.List;

/**
 * 针对表【sys_user(系统用户)】的数据库操作Service实现
 *
 * @author Dcsgo
 * @since 2025-09-22 15:09:11
 */
@Slf4j
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser>
        implements SysUserService {
    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private SysUserRoleMapper sysUserRoleMapper;

    @Override
    public Page<SysUser> getPage(PageDTO pageDTO, SysUserQueryDTO sysUserQueryDTO) {
        // shopId == 1 表示超级管理员，可以看到所有用户信息；否则只能看同店铺下的用户信息
        // TODO: 用户没有店铺ID怎么处理？
        Page<SysUser> page = new Page<>(pageDTO.getCurrent(), pageDTO.getSize());
        return getBaseMapper().selectPage(page,
                new LambdaQueryWrapper<SysUser>()
                        .eq(!AuthUtil.getShopId().equals(1L), SysUser::getShopId, AuthUtil.getShopId())
                        .like(StringUtils.hasText(sysUserQueryDTO.getUsername()), SysUser::getUsername, sysUserQueryDTO.getUsername())
                        .orderByAsc(SysUser::getCreateTime)
        );
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int addUser(SysUserAddDTO sysUserAddDTO) {
        // 1.用户名不能重复
        // 2.如果角色列表不为空，需要添加数据到用户角色关联表中
        SysUser selectedUser = getBaseMapper().selectOne(
                new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, sysUserAddDTO.getUsername())
        );
        if (selectedUser != null) {
            throw new BusinessException("用户名已存在");
        }
        SysUser saveUser = new SysUser();
        BeanUtil.copyProperties(sysUserAddDTO, saveUser);
        saveUser.setPassword(passwordEncoder.encode(sysUserAddDTO.getPassword()));
        saveUser.setCreateUserId(AuthUtil.getUserId());
        saveUser.setCreateTime(new Date());
        int row = getBaseMapper().insert(saveUser);
        log.debug("addUser() return userId:{}", saveUser.getUserId());
        if (!CollectionUtils.isEmpty(sysUserAddDTO.getRoleIdList())) {
            // 向用户角色关联表中添加数据
            // 目前角色数据不大，使用循环插入(Transactional能让我们复用数据库连接对象)
            // TODO: 角色数据量较大时，使用批量插入
            sysUserAddDTO.getRoleIdList().forEach(roleId -> {
                SysUserRole saveUserRole = new SysUserRole();
                saveUserRole.setUserId(saveUser.getUserId());
                saveUserRole.setRoleId(roleId);
                sysUserRoleMapper.insert(saveUserRole);
            });
        }
        return row;
    }

    @Override
    public SysUserVO getUserInfoById(Long id) {
        SysUser user = baseMapper.selectById(id);
        if (user == null) {
            throw new BusinessException("ID为：" + id + "的用户不存在");
        }
        List<Long> roleIdList = sysUserRoleMapper.selectRoleIdListByUserId(id);
        SysUserVO result = new SysUserVO();
        BeanUtil.copyProperties(user, result);
        result.setRoleIdList(roleIdList);
        return result;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public int updateUser(SysUserUpdateDTO sysUserUpdateDTO) {
        // 更新保证用户名唯一性，如果用户名已存在，且不是当前用户，则不允许更新
        // 角色列表不能扩大权限，即新的角色列表不能包含当前登录用户所没有的角色
        // TODO：角色授权有问题，一个店铺下的管理员应该能随意赋予角色给同店铺下的其他用户。
        //  需不需要做成店铺可以有自己的管理员，角色按店铺隔离？
        SysUser oldUserData = getBaseMapper().selectById(sysUserUpdateDTO.getUserId());
        if (oldUserData == null) {
            throw new BusinessException("修改的用户不存在");
        }
        // 新用户名不能已存在
        if (sysUserUpdateDTO.getUsername() != null
                && !oldUserData.getUsername().equals(sysUserUpdateDTO.getUsername())) {
            SysUser selectedUser = getBaseMapper().selectOne(
                    new LambdaQueryWrapper<SysUser>()
                            .eq(SysUser::getUsername, sysUserUpdateDTO.getUsername())
            );
            if (selectedUser != null) {
                throw new BusinessException("用户名已存在");
            }
        }
        List<Long> loginUserRoleIdList = sysUserRoleMapper.selectRoleIdListByUserId(AuthUtil.getUserId());
        // 不是超级管理员的人不能随意授予角色
        if (!AuthUtil.getShopId().equals(1L)) {
            if (CollectionUtils.isEmpty(loginUserRoleIdList)
                    || !new HashSet<>(loginUserRoleIdList).containsAll(sysUserUpdateDTO.getRoleIdList())) {
                throw new BusinessException("非法授予角色，你只能给其他用户授予你拥有的角色");
            }
        }
        // 新密码需要加密了再放入到数据库
        if (sysUserUpdateDTO.getPassword() != null
                && !sysUserUpdateDTO.getPassword().equals(oldUserData.getPassword())) {
            sysUserUpdateDTO.setPassword(passwordEncoder.encode(sysUserUpdateDTO.getPassword()));
        }
        SysUser saveData = new SysUser();
        //Bug note: 不要用Spring 的 BeanUtils，它不会处理枚举类型到Integer类型的转换
        BeanUtil.copyProperties(sysUserUpdateDTO, saveData);
        int row = getBaseMapper().updateById(saveData);
        // 删除原有的角色数据，插入新的角色数据（注意让用户没有角色的情况-把一个用户的角色全删了）
        sysUserRoleMapper.delete(
                new LambdaQueryWrapper<SysUserRole>()
                        .eq(SysUserRole::getUserId, sysUserUpdateDTO.getUserId())
        );
        //TODO: 角色数据量较大时，使用批量插入
        sysUserUpdateDTO.getRoleIdList().forEach(roleId -> {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(sysUserUpdateDTO.getUserId());
            sysUserRole.setRoleId(roleId);
            sysUserRoleMapper.insert(sysUserRole);
        });
        //TODO: 修改用户角色权限，清除相关缓存数据，如被修改用户所缓存的菜单数据
        return row;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public int removeUserById(Long id) {
        SysUser user = this.baseMapper.selectById(id);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        // 超级管理员（shopId == 1）不能删除（用户的shopId可能为null）
        if (user.getShopId() != null && user.getShopId().equals(1L)) {
            throw new BusinessException("超级管理员不允许被删除");
        }
        // 删除用户角色关联表中的数据
        int row = sysUserRoleMapper.delete(
                new LambdaQueryWrapper<SysUserRole>()
                        .eq(SysUserRole::getUserId, id)
        );
        // 删除用户
        row += this.baseMapper.deleteById(id);
        return row;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public int removeUserByIds(List<Long> ids) {
        if (ids.contains(1L)) {
            throw new BusinessException("超级管理员不允许被删除");
        }
        int row = sysUserRoleMapper.delete(
                new LambdaQueryWrapper<SysUserRole>()
                        .in(SysUserRole::getUserId, ids)
        );
        row += this.baseMapper.deleteBatchIds(ids);
        return row;
    }
}




